#!/usr/bin/env python
import sys
sys.stdout


GRAMMAR="JavaGrammar"
PACKAGE="JavaPackage"
COMPOSITION="ProductionComposition"
INTERFACE="ProductionInterface"
LIST="ProductionList"
ONEOF="ProductionEnum"
ENUMESET="ProductionEnumSet"
COMPONENT="ProductionReference"
LITERAL="ProductionLeaf"


def to_att(element, final,  **kwargs ):
	"turn kw, into xml attribute"
	res='<'+element+" "
	att = [k+'="'+v+'"' for k,v in kwargs.items() ]
	res+=" ".join(att)
	if final:
		res+='/>'
	else:
		res+='>'
	return res
	
class Rule(object):
	"versatile class that handles composite rules elements"
	def __init__(self, rule):
		self.literal = (rule.lower()==rule )
		self.optional = rule.endswith("?") and len(rule)>1
		# find the field name
		if self.optional :
			rule = rule[:-1] # remove the trailing ?
		self.value = rule
		



def parse( out=sys.stdout ):
	"parses grammar.txt file"
	objects={}
	packages=[]
	current_type=None
	current_package=None
	linen=0
	with open("Grammar.txt") as f:
		for line in f:
			linen+=1
			try:
				if line.strip() == "":
					continue
				if line.startswith(" "*16 ):                            # rule statement
					current_prod = line[16:-1].strip()
					if current_type==COMPOSITION:
						rules = [ Rule(rule.strip()) for rule in current_prod.split() ]
						for rule in rules:
							if rule.literal:
								print >>out, '.withLiteral("'+rule.value+'", '+("true" if rule.optional else "false")+')',
							else:
								print >>out, '.withComponent("'+rule.value+'", '+("true" if rule.optional else "false")+')',
					elif current_type==ONEOF:
						rules = [ rule.strip() for rule in current_prod.split() ]
						for rule in rules:
							print >>out, '.withLiteral("'+rule.strip()+'")',
					elif current_type==INTERFACE:
						print >>out, '.withComponent("'+current_prod+'")',
					else:
						raise Exception("unexpected rule")
				elif line.startswith(" "*8 ):                           # production rule declaration
					if current_type:
						print >>out, ';'
					raw_name = line[8:-1].strip()
					name, kind = raw_name.split(':')
					if not kind:
						current_type=COMPOSITION
						print  >>out,'g.createComposition("'+name+'")',
					elif kind.startswith('l'):
						tuples, refType = kind[1:].rsplit(' ')
						if not tuples:
							tuples=(' ', '', '') #default value
						else:
							tuples=eval(tuples)
						current_type=LIST
						print  >>out,'g.createList("'+name+'", "'+str(tuples[0])+'","'+str(tuples[1])+'","'+str(tuples[2])+'","'+str(refType)+'" );'
						current_type = None
					elif kind.startswith('e'):
						refType = kind[1:].strip()
						current_type=ENUMESET
						print  >>out,'g.createEnumSet("'+name+'", "'+str(refType)+'" );'
						current_type = None
					elif kind.startswith('i'):
						current_type=INTERFACE
						print  >>out,'g.createInterface("'+name+'")',
					else:
						current_type=ONEOF
						print  >>out,'g.createEnum("'+name+'")',
				else:                                                   # package statement
					if current_type:
						print >>out, ";"
						current_type=None
					current_package = line[:-1].strip()[:-1]
					packages+=[current_package]
					print >>out, 'g.createPackage("'+current_package+'");'
					
			except :
				print "Error line ", linen
				raise
	if current_type:
		print >>out, ';'
	return objects, packages


import os
#os.makedirs("../java/net/ericaro/neojavagengen/")
with open("../java/net/ericaro/neojavagengen/JavaGrammar.java", 'w') as out:
	print >>out, """
	package net.ericaro.neojavagengen;
	public class JavaGrammar  {
	public static Grammar parse(Grammar g){
	"""
	parse(out)
	print >>out, """
	return g;
	}
	}
	"""
	
